package com.kun.video.util;

import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.type.CollectionType;
import com.fasterxml.jackson.databind.type.MapType;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.kun.video.exception.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Jackson JSON工具类（线程安全）
 * <p>提供完善的JSON序列化与反序列化能力，支持：
 * <ul>
 *   <li>Java 8+日期时间类型</li>
 *   <li>宽松的未知属性处理</li>
 *   <li>中文字符集与时区</li>
 *   <li>美化格式输出</li>
 * </ul>
 *
 * @author gzc
 */
@SuppressWarnings({"unused", "UnusedReturnValue"})
public final class JacksonUtil {
    private static final Logger log = LoggerFactory.getLogger(JacksonUtil.class);
    /**
     * 映射对象
     */
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    /**
     * 美化json字符串打印
     */
    private static final JsonMapper PRETTY_PRINTER_MAPPER = new JsonMapper();
    /**
     * 时间日期格式
     */
    private static final String STANDARD_FORMAT = "yyyy-MM-dd HH:mm:ss";

    static {
        // 对象的所有字段全部列入序列化
        OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        // 取消默认转换timestamps形式
        OBJECT_MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        // 忽略空Bean转json的错误
        OBJECT_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        // 所有的日期格式都统一为以下的格式，即yyyy-MM-dd HH:mm:ss
        OBJECT_MAPPER.setDateFormat(new SimpleDateFormat(STANDARD_FORMAT));
        // 忽略 在json字符串中存在，但在java对象中不存在对应属性的情况。防止错误
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        // 对象的所有字段全部列入序列化
        PRETTY_PRINTER_MAPPER.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        // 取消默认转换timestamps形式
        PRETTY_PRINTER_MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        // 忽略空Bean转json的错误
        PRETTY_PRINTER_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        // 所有的日期格式都统一为以下的格式，即yyyy-MM-dd HH:mm:ss
        PRETTY_PRINTER_MAPPER.setDateFormat(new SimpleDateFormat(STANDARD_FORMAT));
        // 忽略 在json字符串中存在，但在java对象中不存在对应属性的情况。防止错误
        PRETTY_PRINTER_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 配置缩进
        PRETTY_PRINTER_MAPPER.enable(SerializationFeature.INDENT_OUTPUT);
        DefaultPrettyPrinter printer = new DefaultPrettyPrinter();
        printer.indentArraysWith(new DefaultIndenter());
        PRETTY_PRINTER_MAPPER.setDefaultPrettyPrinter(printer);
    }

    /**
     * 获取json字符串的类型枚举
     */
    public static JsonNodeType getJsonStrType(String jsonStr) {
        JsonNode jsonNode = parseJsonObj(jsonStr);
        return jsonNode != null ? jsonNode.getNodeType() : null;
    }

    public static <T> T toBean(String jsonStr, Class<T> cls) {
        if (!checkJsonParam(jsonStr)) {
            return null;
        }
        T result = null;
        try {
            result = OBJECT_MAPPER.readValue(jsonStr, cls);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return result;
    }

    public static <T> T toBean(String jsonStr, TypeReference<T> typeReference) {
        if (!checkJsonParam(jsonStr)) {
            return null;
        }
        T result = null;
        try {
            result = OBJECT_MAPPER.readValue(jsonStr, typeReference);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return result;
    }

    public static <T> T parseObject(String jsonStr, Class<T> cls) {
        if (!checkJsonParam(jsonStr)) {
            return null;
        }
        T result = null;
        try {
            result = OBJECT_MAPPER.readValue(jsonStr, cls);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return result;
    }

    public static <T> T parseObject(String jsonStr, TypeReference<T> typeReference) {
        if (!checkJsonParam(jsonStr)) {
            return null;
        }
        T result = null;
        try {
            result = OBJECT_MAPPER.readValue(jsonStr, typeReference);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return result;
    }

    public static <T> T parseObject(File file, Class<T> cls) {
        if (!checkJsonParam(file)) {
            return null;
        }
        T result = null;
        try {
            result = OBJECT_MAPPER.readValue(file, cls);
        } catch (IOException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return result;
    }


    public static <T> T parseArray(String jsonStr, TypeReference<T> reference) {
        if (!checkJsonParam(jsonStr)) {
            return null;
        }
        T result = null;
        try {
            result = OBJECT_MAPPER.readValue(jsonStr, reference);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return result;
    }

    public static <T> T parseArray(String jsonStr, Class<T> cls) {
        if (!checkJsonParam(jsonStr)) {
            return null;
        }
        T result = null;
        try {
            result = OBJECT_MAPPER.readValue(jsonStr, cls);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return result;
    }

    public static <T> T parseArray(String jsonStr, JavaType beanJavaType) {
        if (!checkJsonParam(jsonStr)) {
            return null;
        }
        T result = null;
        try {
            result = OBJECT_MAPPER.readValue(jsonStr, beanJavaType);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return result;
    }


    public static <V> List<V> parseList(String jsonStr, Class<V> listValueCls) {
        if (!checkJsonParam(jsonStr)) {
            return null;
        }
        List<V> result = null;
        try {
            CollectionType javaType = OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, listValueCls);
            result = OBJECT_MAPPER.readValue(jsonStr, javaType);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return result;
    }

    public static <V> List<V> parseList(Object obj, Class<V> listValueCls) {
        if (!checkJsonParam(obj)) {
            return null;
        }
        List<V> result = null;
        if (ObjUtil.isNotEmpty(obj)) {
            if (obj instanceof String jsonStr) {
                result = parseList(jsonStr, listValueCls);
            } else {
                result = parseList(toJsonStr(obj), listValueCls);
            }
        }
        return result;
    }

    public static <V, L extends List<V>> L parseList(String jsonStr, Class<L> listCls, Class<V> listValueCls) {
        if (!checkJsonParam(jsonStr)) {
            return null;
        }
        L result = null;
        try {
            CollectionType javaType = OBJECT_MAPPER.getTypeFactory().constructCollectionType(listCls, listValueCls);
            result = OBJECT_MAPPER.readValue(jsonStr, javaType);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return result;
    }

    public static <V, L extends List<V>> L parseList(String jsonStr, Class<L> listCls, JavaType valueJavaType) {
        if (!checkJsonParam(jsonStr)) {
            return null;
        }
        L result = null;
        try {
            CollectionType javaType = OBJECT_MAPPER.getTypeFactory().constructCollectionType(listCls, valueJavaType);
            result = OBJECT_MAPPER.readValue(jsonStr, javaType);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return result;
    }

    public static <V, L extends List<V>> L parseList(Object obj, Class<L> listCls, Class<V> listValueCls) {
        if (!checkJsonParam(obj)) {
            return null;
        }
        L result = null;
        if (ObjUtil.isNotEmpty(obj)) {
            if (obj instanceof String jsonStr) {
                result = parseList(jsonStr, listCls, listValueCls);
            } else {
                result = parseList(toJsonStr(obj), listCls, listValueCls);
            }
        }
        return result;
    }


    public static <V> Set<V> parseSet(String jsonStr, Class<V> setValueCls) {
        if (!checkJsonParam(jsonStr)) {
            return null;
        }
        Set<V> result = null;
        try {
            CollectionType javaType = OBJECT_MAPPER.getTypeFactory().constructCollectionType(Set.class, setValueCls);
            result = OBJECT_MAPPER.readValue(jsonStr, javaType);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return result;
    }

    public static <V> Set<V> parseSet(Object obj, Class<V> setValueCls) {
        if (!checkJsonParam(obj)) {
            return null;
        }
        Set<V> result = null;
        if (ObjUtil.isNotEmpty(obj)) {
            if (obj instanceof String jsonStr) {
                result = parseSet(jsonStr, setValueCls);
            } else {
                result = parseSet(toJsonStr(obj), setValueCls);
            }
        }
        return result;
    }

    public static <V, L extends Set<V>> L parseSet(String jsonStr, Class<L> setCls, Class<V> setValueCls) {
        if (!checkJsonParam(jsonStr)) {
            return null;
        }
        L result = null;
        try {
            CollectionType javaType = OBJECT_MAPPER.getTypeFactory().constructCollectionType(setCls, setValueCls);
            result = OBJECT_MAPPER.readValue(jsonStr, javaType);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return result;
    }

    public static <V, L extends Set<V>> L parseSet(Object obj, Class<L> setCls, Class<V> setValueCls) {
        if (!checkJsonParam(obj)) {
            return null;
        }
        L result = null;
        if (ObjUtil.isNotEmpty(obj)) {
            if (obj instanceof String jsonStr) {
                result = parseSet(jsonStr, setCls, setValueCls);
            } else {
                result = parseSet(toJsonStr(obj), setCls, setValueCls);
            }
        }
        return result;
    }

    public static <V, L extends Set<V>> L parseSet(String jsonStr, Class<L> setCls, JavaType valueJavaType) {
        if (!checkJsonParam(jsonStr)) {
            return null;
        }
        L result = null;
        try {
            CollectionType javaType = OBJECT_MAPPER.getTypeFactory().constructCollectionType(setCls, valueJavaType);
            result = OBJECT_MAPPER.readValue(jsonStr, javaType);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return result;
    }

    public static <K, V> Map<K, V> parseMap(String jsonStr, Class<K> keyCls, Class<V> valueCls) {
        if (!checkJsonParam(jsonStr)) {
            return null;
        }
        Map<K, V> result = null;
        try {
            MapType javaType = OBJECT_MAPPER.getTypeFactory().constructMapType(Map.class, keyCls, valueCls);
            result = OBJECT_MAPPER.readValue(jsonStr, javaType);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return result;
    }

    public static <K, V> Map<K, V> parseMap(String jsonStr, JavaType keyJavaType, JavaType valueJavaType) {
        if (!checkJsonParam(jsonStr)) {
            return null;
        }
        Map<K, V> result = null;
        try {
            MapType javaType = OBJECT_MAPPER.getTypeFactory().constructMapType(Map.class, keyJavaType, valueJavaType);
            result = OBJECT_MAPPER.readValue(jsonStr, javaType);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return result;
    }

    public static <K, V> Map<K, V> parseMap(Object obj, Class<K> keyCls, Class<V> valueCls) {
        if (!checkJsonParam(obj)) {
            return null;
        }
        Map<K, V> result = null;
        if (ObjUtil.isNotEmpty(obj)) {
            if (obj instanceof String jsonStr) {
                result = parseMap(jsonStr, keyCls, valueCls);
            } else {
                result = parseMap(toJsonStr(obj), keyCls, valueCls);
            }
        }
        return result;
    }

    public static <M extends Map<K, V>, K, V> Map<K, V> parseMap(String jsonStr, Class<M> mapCls, Class<K> keyCls, Class<V> valueCls) {
        if (!checkJsonParam(jsonStr)) {
            return null;
        }
        Map<K, V> result = null;
        try {
            MapType javaType = OBJECT_MAPPER.getTypeFactory().constructMapType(mapCls, keyCls, valueCls);
            result = OBJECT_MAPPER.readValue(jsonStr, javaType);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return result;
    }


    public static String toJsonStr(Object obj) {
        if (!checkJsonParam(obj)) {
            return null;
        }
        String jsonStr = null;
        try {
            jsonStr = OBJECT_MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return jsonStr;
    }

    public static String toJsonPrettyStr(Object obj) {
        if (!checkJsonParam(obj)) {
            return null;
        }
        String jsonStr = null;
        try {
            jsonStr = PRETTY_PRINTER_MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return jsonStr;
    }

    public static byte[] toBytes(Object obj) {
        if (!checkJsonParam(obj)) {
            return null;
        }
        byte[] bytes = null;
        try {
            bytes = OBJECT_MAPPER.writeValueAsBytes(obj);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return bytes;
    }

    public static void toFile(File file, Object obj) {
        try {
            OBJECT_MAPPER.writeValue(file, obj);
        } catch (Exception e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
    }


    public static JsonNode parseJsonObj(String jsonStr) {
        if (!checkJsonParam(jsonStr)) {
            return null;
        }
        JsonNode jsonNode = null;
        try {
            jsonNode = OBJECT_MAPPER.readTree(jsonStr);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return jsonNode;
    }

    public static JsonNode parseJsonObj(Object obj) {
        if (!checkJsonParam(obj)) {
            return null;
        }
        return OBJECT_MAPPER.valueToTree(obj);
    }

    public static String toJsonStr(JsonNode jsonNode) {
        if (!checkJsonParam(jsonNode)) {
            return null;
        }
        String jsonStr = null;
        try {
            jsonStr = OBJECT_MAPPER.writeValueAsString(jsonNode);
        } catch (JsonProcessingException e) {
            Assert.throwBizException(e, "JSON转换异常");
        }
        return jsonStr;
    }

    /**
     * JsonNode是一个抽象类，不能实例化，创建JSON树形模型，得用JsonNode的子类ObjectNode，用法和JSONObject大同小异
     */
    public static ObjectNode newJsonObject() {
        return OBJECT_MAPPER.createObjectNode();
    }

    /**
     * 创建JSON数组对象，就像JSONArray一样用
     */
    public static ArrayNode newJsonArray() {
        return OBJECT_MAPPER.createArrayNode();
    }


    /**
     * 以下是从JsonNode对象中获取key值的方法
     */
    public static String getString(JsonNode jsonObject, String key) {
        if (!checkJsonParam(jsonObject)) {
            return "";
        }
        return jsonObject.get(key).asText();
    }

    public static Integer getInteger(JsonNode jsonObject, String key) {
        if (!checkJsonParam(jsonObject)) {
            return null;
        }
        return jsonObject.get(key).asInt();
    }

    public static Boolean getBoolean(JsonNode jsonObject, String key) {
        if (!checkJsonParam(jsonObject)) {
            return null;
        }
        return jsonObject.get(key).asBoolean();
    }

    public static JsonNode getJsonObject(JsonNode jsonObject, String key) {
        if (!checkJsonParam(jsonObject)) {
            return null;
        }
        return jsonObject.get(key);
    }

    /**
     * 校验json参数是否正确
     *
     * @param jsonParam json参数
     * @return 是否通过校验
     */
    public static boolean checkJsonParam(Object jsonParam) {
        boolean isPass = false;
        if (ObjUtil.isNotEmpty(jsonParam)) {
            isPass = true;
        }
        if (jsonParam instanceof String jsonStr) {
            if (StrUtil.isNotBlank(jsonStr)) {
                isPass = true;
            }
        }
        return isPass;
    }

    /**
     * 获取类型工厂对象
     *
     * @return 类型工厂对象
     */
    public static TypeFactory getTypeFactory() {
        return OBJECT_MAPPER.getTypeFactory();
    }
}